#pragma once
#include <utility>
namespace MySTL
{
    template<typename T1, typename T2>
    struct Pair
    {
        using first_type = T1;
        using second_type = T2;

        T1 first;
        T2 second;

        Pair() = default;
        Pair(const T1 &f, const T2 &s) :first(f), second(s){}
        Pair(T1 &&f, T2 &&s) :first(std::move(f)), second(std::move(s)){}

        template<typename U, typename V>
        Pair(const Pair<U, V> &o) : first(o.first), second(o.second){}

        template<typename U, typename V>
        Pair(Pair<U, V> &&o) : first(std::move(o.first)), second(std::move(o.second)){}

        template<typename U, typename V>
        Pair<T1, T2> &operator =(const Pair<U, V> &o){ first = o.first;    second = o.second;    return *this; }
        template<typename U, typename V>
        Pair<T1, T2> &operator =(Pair<U, V> &&o){ first = std::move(o.first); second = std::move(o.second); return *this; }

        template<typename U, typename V>
        bool operator == (const Pair<U, V> &cmp)
        {
            if (cmp.first != this->first || cmp.second != this->second)
                return false;
            return true;
        }

        template<typename U, typename V>
        bool operator !=(const Pair<U, V> &cmp)
        {
            return !operator==(cmp);
        }

        template<typename U, typename V>
        bool operator <(const Pair<U, V> &cmp)
        {
            if (this->first > cmp.first || this->second > cmp.second)
                return false;

            return true;
        }

        template<typename U, typename V>
        bool operator >(const Pair<U, V> &cmp)
        {
            return !operator< (cmp);
        }
    };

    template<typename T1, typename T2>
    Pair<typename std::remove_reference<T1>::type, typename std::remove_reference<T2>::type>
        Make_Pair(T1 &&f, T2 &&s)
    {
            if (typename std::is_rvalue_reference<decltype(f)>::value)
                return{ std::move(f), std::move(s) };
            else
                return Pair<
                typename std::remove_reference<T1>::type,
                typename std::remove_reference<T2>::type
                >(f, s);
        }
}